/**
 * sunui-extends.js for sunui
 * 
 * author：1940694428@qq.com
 * 
 * 2020.05.12
 * 
 * **/
// const regeneratorRuntime = require("regenerator-runtime");

module.exports = {
	version: "last update：2020.05.12 , veriosn：1.0.0",
	/*判断一个元素是否在数组中*/
	contains(arr, val) {
		return arr.indexOf(val) != -1 ? true : false;
	},

	// 查找数组最小值
	arrayMin(arr) {
		return Math.min(...arr);
	},
	// 从数组中移除 falsey 值
	arrayCompact(arr) {
		return arr.filter(Boolean);
	},

	// 数组中重复的值计数
	arrCount(arr, value) {
		return arr.reduce((a, v) => v === value ? a + 1 : a + 0, 0);
	},
	// 返回两个数组差异
	arrayDiff(a, b) {
		const s = new Set(b);
		return a.filter(x => !s.has(x));
	},
	// 判断数组元素是否重复
	isArrRepeat(arr) {
		let _arr = arr.sort();
		console.log(_arr);
		for (let i = 0; i < _arr.length; i++) {
			if (_arr[i] === _arr[i + 1]) {
				return true;
			}
		}
		return false;
	},

	/**
	 * @param  {arr} 数组
	 * @param  {fn} 回调函数
	 * @return {undefined}
	 */
	each(arr, fn) {
		fn = fn || Function;
		let a = [];
		let args = Array.prototype.slice.call(arguments, 1);
		for (let i = 0; i < arr.length; i++) {
			let res = fn.apply(arr, [arr[i], i].concat(args));
			if (res != null) a.push(res);
		}
	},
	/**
	 * @param  {arr} 数组
	 * @param  {fn} 回调函数
	 * @param  {thisObj} this指向
	 * @return {Array} 
	 */
	map(arr, fn, thisObj) {
		let scope = thisObj || window;
		let a = [];
		for (let i = 0, j = arr.length; i < j; ++i) {
			let res = fn.call(scope, arr[i], i, this);
			if (res != null) a.push(res);
		}
		return a;
	},

    /* JS实现根据两点经纬度位置获取距离：end */
    
    
    /* 根据总数和每页的page，查询分页的总条数
    count:分页总数
    limit:单条分页查询的条数
    */
    pagingSum(count, limit) {
    	let pageSum = 0 //总分页条数
    	if (count > limit) {
    		let sum = count % limit //判断是否有余数，为0：相除为整数，否则有余数，在“分页总条数”基础+1
    		if (sum == 0) {
    			pageSum = count / limit
    		} else {
    			pageSum = parseInt(count / limit) + 1
    		}
    	} else {
    		pageSum = 1
    	}
    	return pageSum
    },
	assignObject (target,source,excludes){
			 if(typeof target  === 'object' && target!==null){
				 Object.keys(target).forEach((key)=>{
					 if(!(excludes==null?void 0:excludes.includes(key))){
						 target[key]=source[key];
						 
					 }
				 })
			 }
			 return target
	},
	
	/**
	 * @param  {arr} 数组
	 * @param  {type} 1：从小到大   2：从大到小   3：随机
	 * @return {Array}
	 */
	sort(arr, type = 1) {
		return arr.sort((a, b) => {
			switch (type) {
				case 1:
					return a - b;
				case 2:
					return b - a;
				case 3:
					return Math.random() - 0.5;
				default:
					return arr;
			}
		})
	},

	/*去重*/
	arrayUnique(arr) {
		if (Array.hasOwnProperty('from')) {
			return Array.from(new Set(arr));
		} else {
			let n = {},
				r = [];
			for (let i = 0; i < arr.length; i++) {
				if (!n[arr[i]]) {
					n[arr[i]] = true;
					r.push(arr[i]);
				}
			}
			return r;
		}
		// 注：上面 else 里面的排重并不能区分 2 和 '2'，但能减少用indexOf带来的性能
		/* 正确排重
		if ( Array.hasOwnProperty('from') ) {
		    return Array.from(new Set(arr))
		}else{
		    let r = [], NaNBol = true
		    for(let i=0; i < arr.length; i++) {
		        if (arr[i] !== arr[i]) {
		            if (NaNBol && r.indexOf(arr[i]) === -1) {
		                r.push(arr[i])
		                NaNBol = false
		            }
		        }else{
		            if(r.indexOf(arr[i]) === -1) r.push(arr[i])
		        }
		    }
		    return r
		}
		 */
	},

	/*求两个集合的并集*/
	union(a, b) {
		let newArr = a.concat(b);
		return this.arrayUnique(newArr);
	},

	/*求两个集合的交集*/
	intersect(a, b) {
		let _this = this;
		a = this.arrayUnique(a);
		return this.map(a, function(o) {
			return _this.contains(b, o) ? o : null;
		});
	},

	/*删除其中一个元素*/
	arrayRemove(arr, ele) {
		let index = arr.indexOf(ele);
		if (index > -1) {
			arr.splice(index, 1);
		}
		return arr;
	},

	/*删除某一项数组*/
	arraySplice(arr, index) {
		arr.splice(Number(index), 1);
		return arr;
	},

	/*将类数组转换为数组的方法*/
	formArray(ary) {
		let arr = [];
		if (Array.isArray(ary)) {
			arr = ary;
		} else {
			arr = Array.prototype.slice.call(ary);
		};
		return arr;
	},

	/*最大值*/
	max(arr) {
		return Math.max.apply(null, arr);
	},

	/*最小值*/
	min(arr) {
		return Math.min.apply(null, arr);
	},

	/*求和*/
	sum(arr) {
		return arr.reduce((pre, cur) => {
			return pre + cur
		});
	},

	/*平均值*/
	average(arr) {
		return this.sum(arr) / arr.length;
	},


	/**
	 * 转义要在正则表达式中使用的字符串(特殊字符)
	 * @param {String} str '(test)' 
	 * @return {RegExp} "\(test\)"
	 * */
	escapeRegExp(str) {
		return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
	},
	/**
	 * @param {String} hex '#f00' 
	 * @return {String} 'rgba(xx,xx,xx)'
	 * @example toHex('#f00')
	 * */
	toRgba(hex) {
		const extendHex = shortHex =>
			'#' + shortHex.slice(shortHex.startsWith('#') ? 1 : 0).split('').map(x => x + x).join('');
		const extendedHex = hex.slice(hex.startsWith('#') ? 1 : 0).length === 3 ? extendHex(hex) : hex;
		return `rgb(${parseInt(extendedHex.slice(1), 16) >> 16}, ${(parseInt(extendedHex.slice(1), 16) & 0x00ff00) >> 8}, ${parseInt(extendedHex.slice(1), 16) & 0x0000ff})`;
	},


	/**
	 * @param {Number} r 
	 * @param {Number} g 
	 * @param {Number} b
	 * @return {String} '#000'
	 * @example toHex(0,0,0)
	 * */
	toHex(r, g, b) {
		return '#' + ((r << 16) + (g << 8) + b).toString(16).padStart(6, '0');
	},

	/**
	 * 设置和获取同步缓存
	 * @param {String} key 设置key
	 * @param {Any} value 缓存任意值
	 * @return {Any} 返回版本信息
	 */
	setCache(key, value) {
		wx.setStorageSync(key, JSON.stringify(value));
	},

	getCache(key) {
		try {
			return JSON.parse(wx.getStorageSync(key));
		} catch (e) {
			//TODO handle the exception
			return wx.getStorageSync(key);
		}
	},

	removeCache(key) {
		wx.removeStorageSync(key);
	},

	clearCache() {
		wx.clearStorageSync();
	},

	// 获取是否闰年
	dateLeapYear() {
		let year = new Date().getFullYear();
		return ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
	},

	// 获取当前时间戳 - 13位转为10位，然后*1000再parseInt
	dateStamp(digits = 10) {
		digits = Number(digits);
		switch (digits) {
			case 10:
				return Math.round(new Date().getTime() / 1000).toString();
			case 13:
				return new Date().getTime().toString();
		}
	},

	// 获取到当前的时间 获取年、月、日

	getCurrentTime() {
		// 创建一个 Date 对象
		const currentDate = new Date();

		// 获取年、月、日
		const year = currentDate.getFullYear();
		const month = ("0" + (currentDate.getMonth() + 1)).slice(-2);
		const day = ("0" + currentDate.getDate()).slice(-2);

		// 拼接为所需的格式，例如：2023-09-02
		const formattedDate = `${year}-${month}-${day}`;
		return formattedDate
	}


	/**
	 * 类型判断
	 * @param {String,Number} number 传入的数值
	 * @return {String} 返回字符串
	 */
	toDigit(any) {
		return any.toString().replace(/^(\d)$/, `0$1`);
	},

	/**
	 *秒转成分钟： 如 100 => 01:40
	 *
	 * @param {*} sec
	 * @returns
	 */
	dateStoM(sec) {
		const MINUTE = 60;
		const minute = Math.floor(sec / MINUTE);
		const surplusSec = sec % MINUTE;
		return `${this.toDigit(minute)}:${this.toDigit(surplusSec)}`;
	},


	/**
	 * 传入13位时间戳获取距离当前时间
	 * @param {*} sec
	 * @return {String} 3天前 返回距离时间具体描述
	 */
	dateDistance(timestamp) {
		let publishTime = Number(timestamp) / 1000,
			date = new Date(publishTime * 1000),
			Y = this.toDigit(date.getFullYear()),
			M = this.toDigit(date.getMonth() + 1),
			D = this.toDigit(date.getDate()),
			H = this.toDigit(date.getHours()),
			m = this.toDigit(date.getMinutes()),
			s = this.toDigit(date.getSeconds());
		let nowTime = new Date().getTime() / 1000,
			diffValue = nowTime - publishTime,
			diff_days = parseInt(diffValue / 86400),
			diff_hours = parseInt(diffValue / 3600),
			diff_minutes = parseInt(diffValue / 60),
			diff_secodes = parseInt(diffValue);

		if (diff_days > 0 && diff_days < 3) {
			return diff_days + "天前";
		} else if (diff_days <= 0 && diff_hours > 0) {
			return diff_hours + "小时前";
		} else if (diff_hours <= 0 && diff_minutes > 0) {
			return diff_minutes + "分钟前";
		} else if (diff_secodes < 60) {
			if (diff_secodes <= 0) {
				return "刚刚";
			} else {
				return diff_secodes + "秒前";
			}
		} else if (diff_days >= 3 && diff_days < 30) {
			return M + '-' + D + ' ' + H + ':' + m;
		} else if (diff_days >= 30) {
			return Y + '-' + M + '-' + D + ' ' + H + ':' + m;
		}
	},
	/**
	 * 获取当天周几
	 * @param {} 
	 * @return {String} "星期x" 返回周几
	 */
	dateWeek() {
		let day = new Date().getDay();
		let week = new Array("星期日", "星期一", "星期二", "星期三", "星期四", "星期五");
		return week[day];
	},
	/**
	 * 获取当天是否周六周日
	 * @param {} 
	 * @return {Boolean} true/false 返回是否周六周日
	 */
	dateWeekend() {
		let _date = new Date();
		let _nowTime = _date.getTime();
		let _week = _date.getDay();
		let _yearMonthDay =
			`${_date.getFullYear()}-${_date.getMonth()+1>=10?_date.getMonth()+1:'0'+_date.getMonth()+1}-${_date.getDate()>=10?_date.getDate():'0'+_date.getDate()}`;
		let _dayLongTime = 24 * 60 * 60 * 1000;
		let _furtureSundayTimes = _nowTime + (7 - _week) * _dayLongTime;
		let _furtureSaturdayTimes = _nowTime + (6 - _week) * _dayLongTime;
		let _mealSunDay;
		let _mealSaturDay;
		_furtureSundayTimes = new Date(_furtureSundayTimes);
		_furtureSaturdayTimes = new Date(_furtureSaturdayTimes);
		let _satYear = _furtureSaturdayTimes.getFullYear();
		let _satMonth = _furtureSaturdayTimes.getMonth() + 1;
		let _satDay = _furtureSaturdayTimes.getDate();
		let _sunYear = _furtureSundayTimes.getFullYear();
		let _sunMonth = _furtureSundayTimes.getMonth() + 1;
		let _sunDay = _furtureSundayTimes.getDate();
		_satMonth = _satMonth >= 10 ? _satMonth : '0' + _satMonth;
		_satDay = _satDay >= 10 ? _satDay : '0' + _satDay;
		_sunMonth = _sunMonth >= 10 ? _sunMonth : '0' + _sunMonth;
		_sunDay = _sunDay >= 10 ? _sunDay : '0' + _sunDay;
		_mealSunDay = _satYear + '-' + _satMonth + '-' + _satDay;
		_mealSaturDay = _sunYear + '-' + _sunMonth + '-' + _sunDay;
		let _weekendDay = [_mealSunDay, _mealSaturDay];
		let _isWeekend = _weekendDay.indexOf(_yearMonthDay) != -1;
		// 最近的周六/周日 _weekendDay.  _isWeekend:true | false
		return _isWeekend;
	},
	/**
	 * 传入具体日期返回13位时间戳
	 * @param {String} date "2020-07-13 18:00"
	 * @return {String} "1589257080657"
	 */
	dateToStamp(stamp) {
		return new Date(stamp.replace(/-/g, '/')).getTime();
		// return new Date(stamp).getTime();
	},
	/**
	 * 传入13位时间戳
	 * @param {String,Number} timestamp "1589257080657"
	 * @param {String} format "Y-M-D Y-M-D-h-m-s" 
	 * @return {String} "2020*01*05 10:00"
	 */
	dateFormat(timestamp, format) {
		format = format || `Y-M-D`;
		const cur = Number(timestamp) ? new Date(Number(timestamp)) : new Date();
		const year = cur.getFullYear();
		const month = this.toDigit(cur.getMonth() + 1);
		const day = this.toDigit(cur.getDate());
		const hour = this.toDigit(cur.getHours());
		const minute = this.toDigit(cur.getMinutes());
		const second = this.toDigit(cur.getSeconds());
		return format.replace(/Y|M|D|h|m|s/g, function(matches) {
			return ({
				Y: year,
				M: month,
				D: day,
				h: hour,
				m: minute,
				s: second
			})[matches];
		});
	},

	/**
	 * 格式化时间
	 * 
	 * @param  {time} 时间
	 * @param  {cFormat} 格式
	 * @return {String} 字符串
	 *
	 * @example formatTime('2018-1-29', '{y}/{m}/{d} {h}:{i}:{s}') // -> 2018/01/29 00:00:00
	 */
	formatTime(time, cFormat) {
		if (arguments.length === 0) return null
		if ((time + '').length === 10) {
			time = +time * 1000
		}

		let format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}',
			date
		if (typeof time === 'object') {
			date = time
		} else {
			date = new Date(time)
		}

		let formatObj = {
			y: date.getFullYear(),
			m: date.getMonth() + 1,
			d: date.getDate(),
			h: date.getHours(),
			i: date.getMinutes(),
			s: date.getSeconds(),
			a: date.getDay()
		}
		let time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
			let value = formatObj[key]
			if (key === 'a') return ['一', '二', '三', '四', '五', '六', '日'][value - 1]
			if (result.length > 0 && value < 10) {
				value = '0' + value
			}
			return value || 0
		})
		return time_str
	},


	/**
	 * 返回指定长度的月份集合
	 * 
	 * @param  {time} 时间
	 * @param  {len} 长度
	 * @param  {direction} 方向：  1: 前几个月;  2: 后几个月;  3:前后几个月  默认 3
	 * @return {Array} 数组
	 * 
	 * @example   dateMonths('2018-1-29', 6, 1)  // ->  ["2018-1", "2017-12", "2017-11", "2017-10", "2017-9", "2017-8", "2017-7"]
	 */
	dateMonths(time, len, direction) {
		direction = isNaN(direction) ? 3 : direction;
		let mm = new Date(time).getMonth() + 1,
			yy = new Date(time).getFullYear(),
			index = mm;

		let cutMonth = function(index) {
			let arr
			if (direction === 1) {
				arr = formatPre(index).reverse()
			} else if (direction === 2) {
				arr = formatNext(index)
			} else {
				arr = formatPre(index).reverse().slice(len / 2).concat(formatNext(index).slice(1, len / 2 + 1))
			}
			return arr.sort(function(t1, t2) {
				return new Date(t1).getTime() - new Date(t2).getTime()
			})
		}

		let formatPre = function(index) {
			let currNum = index,
				preNum = 0,
				currArr = [],
				preArr = []
			if (index - len < 0) {
				preNum = len - currNum
			}
			for (let i = 0; i < currNum; i++) {
				currArr.push([yy + '-' + (currNum - i)])
			}
			for (let i = 1; i <= preNum; i++) {
				preArr.push([(yy - Math.ceil(i / 12)) + '-' + (12 - (i - 1) % 12)])
			}
			return currArr.concat(preArr)
		}

		let formatNext = function(index) {
			let currNum = 12 - index,
				nextNum = 0,
				currArr = [],
				nextArr = []
			if (len - currNum > 0) {
				nextNum = len - currNum
			}
			for (let i = 0; i <= currNum; i++) {
				currArr.push([yy + '-' + (index + i)])
			}
			for (let i = 1; i < nextNum; i++) {
				nextArr.push([(yy + Math.ceil(i / 12)) + '-' + (i % 13 === 0 ? 1 : i % 13)])
			}
			return currArr.concat(nextArr)
		}
		return cutMonth(index)
	},



	/**
	 * 返回指定长度的天数集合
	 * 
	 * @param  {time} 时间
	 * @param  {len} 长度
	 * @param  {direction} 方向： 1: 前几天;  2: 后几天;  3:前后几天  默认 3
	 * @return {Array} 数组
	 *
	 * @example dateDays('2018-1-29', 6) // -> ["2018-1-26", "2018-1-27", "2018-1-28", "2018-1-29", "2018-1-30", "2018-1-31", "2018-2-1"]
	 */
	dateDays(time, len, diretion) {
		let tt = new Date(time)
		let getDay = function(day) {
			let t = new Date(time)
			t.setDate(t.getDate() + day)
			let m = t.getMonth() + 1
			return t.getFullYear() + '-' + m + '-' + t.getDate()
		}
		let arr = []
		if (diretion === 1) {
			for (let i = 1; i <= len; i++) {
				arr.unshift(getDay(-i))
			}
		} else if (diretion === 2) {
			for (let i = 1; i <= len; i++) {
				arr.push(getDay(i))
			}
		} else {
			for (let i = 1; i <= len; i++) {
				arr.unshift(getDay(-i))
			}
			arr.push(tt.getFullYear() + '-' + (tt.getMonth() + 1) + '-' + tt.getDate())
			for (let i = 1; i <= len; i++) {
				arr.push(getDay(i))
			}
		}
		return diretion === 1 ? arr.concat([tt.getFullYear() + '-' + (tt.getMonth() + 1) + '-' + tt.getDate()]) :
			diretion === 2 ? [tt.getFullYear() + '-' + (tt.getMonth() + 1) + '-' + tt.getDate()].concat(arr) : arr
	},


	/**
	 * @param  {s} 秒数
	 * @return {String} 字符串 
	 *
	 * @example formatHMS(3610) // -> 1h0m10s
	 */
	dateStoH(s) {
		let str = ''
		if (s > 3600) {
			str = Math.floor(s / 3600) + 'h' + Math.floor(s % 3600 / 60) + 'm' + s % 60 + 's'
		} else if (s > 60) {
			str = Math.floor(s / 60) + 'm' + s % 60 + 's'
		} else {
			str = s % 60 + 's'
		}
		return str
	},

	/*获取某月有多少天*/
	dateMonthOfDay(timestamp) {
		let date = new Date(Number(timestamp))
		let year = date.getFullYear()
		let mouth = date.getMonth() + 1
		let days

		//当月份为二月时，根据闰年还是非闰年判断天数
		if (mouth == 2) {
			days = (year % 4 == 0 && year % 100 == 0 && year % 400 == 0) || (year % 4 == 0 && year % 100 != 0) ?
				28 : 29
		} else if (mouth == 1 || mouth == 3 || mouth == 5 || mouth == 7 || mouth == 8 || mouth == 10 || mouth ==
			12) {
			//月份为：1,3,5,7,8,10,12 时，为大月.则天数为31；
			days = 31
		} else {
			//其他月份，天数为：30.
			days = 30
		}
		return days
	},

	/*获取某年有多少天*/
	dateYearOfDay(time) {
		let firstDayYear = this.dateFirstDayOfYear(time);
		let lastDayYear = this.dateLastDayOfYear(time);
		let numSecond = (new Date(lastDayYear).getTime() - new Date(firstDayYear).getTime()) / 1000;
		return Math.ceil(numSecond / (24 * 3600));
	},

	/*获取某年的第一天*/
	dateFirstDayOfYear(time) {
		let year = new Date(time).getFullYear();
		return year + "-01-01 00:00:00";
	},

	/*获取某年最后一天*/
	dateLastDayOfYear(time) {
		let year = new Date(time).getFullYear();
		let dateString = year + "-12-01 00:00:00";
		let endDay = this.getMonthOfDay(dateString);
		return year + "-12-" + endDay + " 23:59:59";
	},

	/*获取某个日期是当年中的第几天*/
	dateDayOfYear(time) {
		let firstDayYear = this.dateFirstDayOfYear(time);
		let numSecond = (new Date(time).getTime() - new Date(firstDayYear).getTime()) / 1000;
		return Math.ceil(numSecond / (24 * 3600));
	},

	/*获取某个日期在这一年的第几周*/
	dateDayOfYearWeek(time) {
		let numdays = this.dateDayOfYear(time);
		return Math.ceil(numdays / 7);
	},

	/**
	 * 获取数据类型
	 * @param {Any} any 任意类型
	 * @return {Any} any
	 * 
	 * @example getDataType(null)=>Null;
	 * */
	getDataType(any) {
		let temp = Object.prototype.toString.call(any);
		let type = temp.replace(/\[/g, '').replace(/\]/g, '');
		let index = type.lastIndexOf(" ");
		let str = type.substring(index + 1, type.length);
		return str;
	},
	/**
	 * 是否对象
	 * @param {Object} obj 传入对象
	 * @return {Boolean} 返回true或false
	 */
	isObject(obj) {
		return obj !== null && typeof obj === 'object';
	},


	/**
	 * 是否正则表达式
	 * @param {RegExp} v 传入正则表达式
	 * @return {Boolean} 返回true或false
	 */
	isRegExp(v) {
		return Object.prototype.toString.call(v) === '[object RegExp]';
	},

	/**
	 * 是否未定义
	 * @param {String} v 传入需要校验的值
	 * @return {Boolean} 返回true或false
	 */
	isUndef(v) {
		return v === undefined || v === null;
	},

	/**
	 * 是否已定义
	 * @param {String} v 传入需要校验的值
	 * @return {Boolean} 返回true或false
	 */
	isDef(v) {
		return v !== undefined && v !== null;
	},

	/**
	 * 是否已定义
	 * @param {String} v 传入需要校验的值
	 * @return {Boolean} 返回true或false
	 */
	isString(v) {
		return v.constructor == String;
	},

	/**
	 * 是否已定义
	 * @param {Number} v 传入需要校验的值
	 * @return {Boolean} 返回true或false
	 */
	isNumber(v) {
		return v.constructor == Number;
	},

	/**
	 * 是否已定义
	 * @param {Boolean} v 传入需要校验的值
	 * @return {Boolean} 返回true或false
	 */
	isBoolean(v) {
		return v.constructor == true;
	},

	/**
	 * 是否已定义
	 * @param {Function} v 传入需要校验的值
	 * @return {Boolean} 返回true或false
	 */
	isFunc(v) {
		return v.constructor == Function;
	},

	/**
	 * 是否Array
	 * @param {Array} v 传入需要校验的值
	 * @return {Boolean} 返回true或false
	 */
	isArray(v) {
		return Array.isArray(v);
	},

	// 是否为false - https://www.cnblogs.com/cisum/p/12072873.html
	isTrue(any) {
		let match = ['undefined', 'null', 'NaN', 'false', false, 0, undefined, NaN, ''];
		return match.indexOf(any) > -1 ? false : true;
	},


	/**
	 * 是否存在空格
	 * @param {Object} obj 传入需要校验的值
	 * @return {Boolean} 返回true或false
	 */
	isSpaceObject(obj) {
		return Object.keys(obj).length > 0 ? true : false;
	},

	/**
	 * 是否存在空格
	 * @param {String} str 传入需要校验的值
	 * @return {Boolean} 返回true或false
	 */
	isSpace(str) {
		return /\s/.test(str);
	},
	/**
	 * 是否为符号
	 * @param {Symbol} symbol 传入需要校验的值
	 * @return {Boolean} 返回true或false
	 */
	isSymbol(v) {
		return typeof v === 'symbol';
	},
	/**
	 * [获取当前经纬度]
	 * const map = await this.$map.latlng();
	 * @return {Object}=>{lat:xx,lng:xx}
	 */
	latlng: () => {
		return new Promise((resolve, reject) => {
			wx.getLocation({
				type: 'gcj02',
				success: res => {
					resolve({
						lat: res.latitude,
						lng: res.longitude
					});
				},
				fail: err => {
					reject(err);
				}
			});
		});
	},

	/**
	 * [获取两点间的经纬度距离]
	 * const map = await this.$sun.distance({lat});
	 * @return {Object}=>{lat:xx,lng:xx}
	 */
	distance: ({
		lat1,
		lng1,
		lat2,
		lng2
	}) => {
		let La1 = lat1 * Math.PI / 180.0;
		let La2 = lat2 * Math.PI / 180.0;
		let La3 = La1 - La2;
		let Lb3 = lng1 * Math.PI / 180.0 - lng2 * Math.PI / 180.0;
		let s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(La3 / 2), 2) + Math.cos(La1) * Math.cos(La2) * Math
			.pow(Math.sin(
				Lb3 / 2), 2)));
		s = s * 6378.137;
		s = Math.round(s * 10000) / 10000;
		s = s.toFixed(2);
		return s;
	},
	/**
	 * [传入腾讯地图密钥以获取当前地理位置信息]
	 * const map = await this.$map.location({lat:'xx',lng:'xx',key:'xxxx-xxxx'});
	 * 
	 * 
	 * gcj02不支持国外腾讯地图
	 * 
	 * @return {Object}
	 */
	location: ({
		lat,
		lng,
		key
	}) => {
		return new Promise((resolve, reject) => {
			wx.request({
				url: `https://apis.map.qq.com/ws/geocoder/v1/?location=${lat},${lng}&key=${key}`,
				method: 'GET',
				success: res => {
					res.data.status == 0 ? resolve(res.data.result) : reject(res.data
						.message);
				}
			});
		});
	},

	/**
	 * [传入腾讯地图密钥以获取当前地理位置信息以及当地天气]
	 * const weather = await this.$map.weather({key:xxxx-xxxx});
	 * @return {Object}
	 */
	weather: ({
		key
	}) => {
		return new Promise((resolve, reject) => {
			wx.getLocation({
				type: 'gcj02',
				success: res => {
					wx.request({
						url: `https://apis.map.qq.com/ws/geocoder/v1/?location=${res.latitude},${res.longitude}&key=${key}`,
						method: 'GET',
						success: res => {
							if (res.data.message == 'query ok') {
								let address = res.data.result.address_component;
								wx.request({
									url: `https://wis.qq.com/weather/common`,
									method: 'GET',
									data: {
										source: 'xw',
										weather_type: 'observe|alarm|air|forecast_1h|forecast_24h|index|limit|tips|rise',
										province: `${address.province}`,
										city: `${address.city}`,
										county: `${address.district}`
									},
									success: res => {
										resolve(res.data.data);
									},
									fail: () => {
										reject(res.data.message);
									},
									complete: () => {}
								});
							}
						}
					});
				},
				fail: err => {
					reject(err);
				}
			});
		});
	},

	/**
	 * [选择地图上的地址信息]
	 * const map = await this.$map.chooseLocation({lat,lng});
	 * @return {Object}
	 */
	chooseLocation: ({
		lat,
		lng
	}) => {
		return new Promise((resolve, reject) => {
			wx.chooseLocation({
				latitude: lat,
				longitude: lng,
				success: res => {
					resolve(res);
				},
				fail: err => {
					reject(err);
				}
			});
		});
	},

	/**
	 * [传入经纬度以及腾讯地图密钥获取对应地址信息]
	 * const map = await this.$map.openLocation({lat:xx,lng:xx,key:'xx-xx'});
	 * @return {Null}
	 */
	openLocation: ({
		lat,
		lng,
		key
	}) => {
		return new Promise((resolve, reject) => {
			wx.request({
				url: `https://apis.map.qq.com/ws/geocoder/v1/?location=${lat},${lng}&key=${key}`,
				method: 'GET',
				success: res => {
					try {
						wx.openLocation({
							latitude: res.data.result.location.lat,
							longitude: res.data.result.location.lng,
							name: res.data.result.ad_info.district,
							address: res.data.result.address,
							scale: 18
						});
					} catch (e) {
						//TODO handle the exception
						reject(res.data.message);
					}
				},
				fail: err => {
					reject(err);
				}
			});
		});
	},
	/*随机数范围*/
	random(min, max) {
		if (arguments.length === 2) {
			return Math.floor(min + Math.random() * ((max + 1) - min))
		} else {
			return null;
		}

	},
	moneyFormat(number, decimals, dec_point, thousands_sep) {
		/*
		 * 参数说明：
		 * number：要格式化的数字
		 * decimals：保留几位小数
		 * dec_point：小数点符号
		 * thousands_sep：千分位符号
		 * */
		number = (number + '').replace(/[^0-9+-Ee.]/g, '');
		let n = !isFinite(+number) ? 0 : +number,
			prec = !isFinite(+decimals) ? 0 : Math.abs(decimals),
			sep = (typeof thousands_sep === 'undefined') ? ',' : thousands_sep,
			dec = (typeof dec_point === 'undefined') ? '.' : dec_point,
			s = '',
			toFixedFix = function(n, prec) {
				let k = Math.pow(10, prec);
				return '' + Math.floor(n * k) / k;
			};
		s = (prec ? toFixedFix(n, prec) : '' + Math.floor(n)).split('.');
		let re = /(-?\d+)(\d{3})/;
		// console.log(s)
		while (re.test(s[0])) {
			s[0] = s[0].replace(re, "$1" + sep + "$2");
		}
		if ((s[1] || '').length < prec) {
			s[1] = s[1] || '';
			s[1] += new Array(prec - s[1].length + 1).join('0');
		}
		return s.join(dec);
	},
	/**
	 * 数值转字符串
	 * @param {Number}
	 * @return {String} 
	 */
	numStr(v) {
		return v.toString();
	},
	/**
	 * 数值转字符串
	 * @param {Number} num 当前数字
	 * @param {Number} total 当前总数
	 * @return {String} 返回百分比 
	 */
	numPer(num, total) {
		num = parseFloat(num);
		total = parseFloat(total);
		if (isNaN(num) || isNaN(total)) {
			return "-";
		}
		return total <= 0 ? "0%" : (Math.round(num / total * 10000) / 100.00) + "%";
	},
	/**
	 * 取小数位
	 * @param {String,Number}
	 * @return {String} 
	 */
	numDigit(digit, num = 2) {
		return Number(digit).toFixed(num);
	},
	/**
	 * 取最小数
	 * @param {String,Number}
	 * @return {String} 
	 */
	numMin(v1, v2) {
		return Math.min(Number(v1), Number(v2));
	},
	/**
	 * 取最大数
	 * @param {String,Number}
	 * @return {String} 
	 */
	numMax(v1, v2) {
		return Math.max(Number(v1), Number(v2));
	},
	/**
	 * 返回数的绝对值
	 * @param {String,Number}
	 * @return {String} 
	 */
	numAbs(v) {
		return Math.abs(Number(v));
	},
	/**
	 * 向上取整
	 * @param {String,Number}
	 * @return {String} 
	 */
	numUp(v) {
		return Math.ceil(Number(v));
	},
	/**
	 * 向下取整
	 * @param {String,Number}
	 * @return {String} 
	 */
	numDown(v) {
		return Math.floor(Number(v));
	},
	/**
	 * 去除小数部分
	 * @param {String,Number}
	 * @return {String} 
	 */
	numTrunc(v) {
		return Math.trunc(Number(v));
	},
	/**
	 * 判断是否为正数/负数/零
	 * @param {String,Number}
	 * @return {String} 
	 */
	isSign(v) {
		return Math.sign(Number(v));
	},
	/**
	 * 判断是否为整数
	 * @param {String,Number}
	 * @return {String} 
	 */
	isInt(v) {
		return Number.isInteger(Number(v));
	},
	// 设置页面标题
	title(title) {
		wx.setNavigationBarTitle({
			title
		});
	},

	/**
	 * [URL参数拼接]
	 * @param [url,obj]
	 * @return {String}
	 */

	createURL({
		url,
		obj
	}) {
		return new Promise((resolve, reject) => {
			let props = "";
			for (let p in obj) {
				if (obj[p])
					props += "&" + p + "=" + obj[p];
			}
			resolve(`${url}?${props.substr(1)}`);
		});
	},


	/**
	 * 保留当前页面，跳转到应用内的某个页面
	 * @param {String} url 页面路径
	 * @param {Object} params 页面参数
	 */

	navGo(url, params) {
		this._openInterceptor('navigateTo', url, params);
	},

	/**
	 * 关闭当前页面，跳转到应用内的某个页面
	 * @param {String} url 页面路径
	 * @param {Object} params 页面参数
	 */

	navTo(url, params) {
		this._openInterceptor('redirectTo', url, params);
	},

	/**
	 * 跳转到 tabBar 页面，并关闭其他所有非 tabBar 页面
	 * @param {String} url 页面路径
	 * @param {Object} params 页面参数
	 */

	navSwitch(url, params) {
		this._openInterceptor('switchTab', url, params);
	},

	/**
	 * 关闭所有页面，打开到应用内的某个页面
	 * @param {String} url 页面路径
	 * @param {Object} params 页面参数
	 */

	navRe(url, params) {
		this._openInterceptor('reLaunch', url, params);
	},

	/**
	 * 返回页面
	 * @param {Number} delta 返回层级
	 * @param {None} params 无
	 */
	navBack(delta = 1) {
		wx.navigateBack({
			delta
		});
	},

	/**
	 * 页面跳转封装
	 * @param {String} method 微信JS方法
	 * @param {String} url 页面路径
	 * @param {Object} params 页面参数
	 */

	_openInterceptor(method, url, params) {
		if (this.IsPageNavigating) return;
		this.IsPageNavigating = true;
		params = this.param(params);
		wx[method]({
			url: url + params,
			complete: () => {
				this.IsPageNavigating = false;
			}
		});
	},


	// 授权数据解析
	authParam(obj) {
		if (obj) {
			if (Object.keys(obj).length) {
				return JSON.parse(obj);
			}
		} else {
			return {};
		}
	},


	/**
	 * 将对象解析成url字符串
	 * @param  {Object} obj 参数对象
	 * @param  {Boolean} unEncodeURI 不使用编码
	 * @return {String} 转换之后的url参数
	 */

	param(obj = {}, unEncodeURI) {
		let result = [];

		for (let name of Object.keys(obj)) {
			let value = obj[name];

			result.push(name + '=' + (unEncodeURI ? value : encodeURIComponent(value)));
		}

		if (result.length) {
			return '?' + result.join('&');
		} else {
			return '';
		}
	},

	/**
	 * 将url字符串解析成对象
	 * @param  {String} str 带url参数的地址
	 * @param  {Boolean} unDecodeURI 不使用解码
	 * @return {Object} 转换之后的url参数
	 */

	unparam(str = '', unDecodeURI) {
		let result = {},
			query = str.split('?')[1];

		if (!query) return result;

		let arr = query.split('&');

		arr.forEach((item, idx) => {
			let param = item.split('='),
				name = param[0],
				value = param[1] || '';
			if (name) {
				result[name] = unDecodeURI ? value : decodeURIComponent(value);
			}
		});

		return result;
	},


	// 获取上级页面

	getCurrentPageUrl() {
		let pages = getCurrentPages();
		let currentPage = pages[pages.length - 1];
		let url = currentPage.route;
		return url;
	},

	/**
	 * [微信小程序拦截]
	 * @param [url：地址,param：参数]
	 * @return {Null}
	 */
	weChatAuth(url, param) {
		let parse = JSON.stringify(encodeURIComponent(param));
		if (!wx.getStorageSync('uid')) {
			wx.navigateTo({
				url: `/pages/auth/auth?url=${url}&parse=${parse}`
			});
		} else {
			wx.navigateTo({
				url: `${url}?${param}`
			});
		}
	},

	/**
	 * 获取当前页面路径
	 * @param {}
	 * @return {Object} 
	 */
	getCurrentPath() {
		return this.getCurrentPage().__route__;
	},
	/**
	 * @param {Object} pay 支付参数
	 * @return {Callback} 无
	 * */
	wePay(args, success, fail) {
		wx.requestPayment({
			"provider": args.provider || 'wxpay',
			"timeStamp": args.timeStamp,
			"nonceStr": args.nonceStr,
			"package": args.package,
			"signType": args.signType,
			"paySign": args.paySign,
			"success": (res) => {
				success(JSON.stringify(res));
			},
			"fail": (err) => {
				fail(JSON.stringify(err));
			}
		});
	},
	/**
	 * 校验手机号
	 * @param mobile
	 * @returns {boolean}
	 */
	checkPhone(mobile) {
		return /^[1][0-9]{10}$/.test(mobile)
	},

	/**
	 * 校验纯数字
	 * @param num
	 * @returns {boolean}
	 */
	checkNum(num) {
		return /^[0-9]+$/.test(num)
	},

	/**
	 * 校验用户名：1-20位字符，首字符为字母
	 * @param str
	 * @returns {RegExp}
	 */
	checkUserName(str) {
		return /^[a-zA-Z]{1,20}$/.test(str)
	},

	/**
	 * 校验密码：6-20位，数字、字母、下划线
	 * @param str
	 * @returns {boolean}
	 */
	checkPwd(str) {
		return /^(\\w){6,20}$/.test(str)
	},

	/**
	 * 校验正整数 + 0
	 * @param num
	 * @returns {boolean}
	 */
	checkPositiveInteger(num) {
		return /^[0-9]*[1-9][0-9]*$/.test(num)
	},

	/**
	 * 校验字符串是否为数字
	 * @param str
	 * @returns {boolean}
	 */
	checkNumber(str) {
		let regPos = /^\d+(\.\d+)?$/; //非负浮点数
		let regNeg = /^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$/; //负浮点数
		if (regPos.test(str) || regNeg.test(str)) {
			return true;
		} else {
			return false;
		}
	},
	/**
	 * 校验字符串是否为电子邮箱
	 * @param str
	 * @returns {boolean}
	 */
	checkEmail(str) {
		return /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
			.test(str);
	},
	/**
	 * 小于10补零
	 * @param {String,Number} number 传入的数值
	 * @return {String} 返回字符串
	 */
	toDigit(any) {
		return any.toString().replace(/^(\d)$/, `0$1`);
	},
	/**
	 * 类型判断
	 * @param {Any} value 任意需要判断的参数
	 * @return {String} 返回的类型
	 */
	type(v) {
		return Object.prototype.toString.call(v).split(' ')[1].substr(0, Object.prototype.toString.call(v).split(
				' ')[1].length -
			1);
	},
	/**
	 * 消息
	 * @param {String} key 设置key
	 * @return {NONE} 打印消息
	 */
	toast(title = "提示", icon = "none", duration = "2") {
		wx.showToast({
			title,
			icon,
			duration: Number(duration) * 1e3
		});
	},
	/**
	 * 取小数位
	 * @param {String,Number}
	 * @return {String} 
	 */

	digit(digit, num = 2) {
		return Number(digit).toFixed(num);
	},
	/**
	 * 获取点击元素携带值
	 * @param {Object} e 点击对象
	 * @param {String} elename 点击所获取的具体值
	 * @return {Object,String} getElement 返回对象或者字符串
	 */

	ele(e, elename) {
		return elename ? e.currentTarget.dataset[elename] : e.currentTarget.dataset;
	},
	// 获取任意区间随机数
	random(min, max) {
		return min + Math.floor(Math.random() * (max - min + 1));
	},
	/**
	 * [匹配item是否在数组]
	 * @param [m:延迟时间]
	 * @return [none]
	 */
	delay(m = 3, success) {
		setTimeout(() => {
			success()
		}, m * 1e3);
	},
	/**
	 * [去除所有空格]
	 * @param [str:字符串]
	 * @return str
	 */
	spaceRemove(str) {
		return str.replace(/\s+/g, '');
	},
	/**
	 * [拨打号码]
	 * @param [phoneNumber:手机号]
	 * @return {Null}
	 */
	phone(phoneNumber) {
		wx.makePhoneCall({
			phoneNumber: phoneNumber + ''
		});
	},
	/**
	 * [底部适配(iphone XR\iphone X\ iphone Xs Max)]
	 * @return {Boolean}
	 */
	isIphoneX() {
		return new Promise((resolve, reject) => {
			wx.getSystemInfo({
				success(res) {
					resolve(res.model.search('iPhone X') != -1);
				},
				fail(err) {
					reject(err);
				}
			});
		});
	},
	/**
	 * [sleep睡眠时间]
	 * @return {Boolean}
	 */
	sleep(numberMillis) {
		let now = new Date();
		let exitTime = now.getTime() + numberMillis;
		while (true) {
			now = new Date();
			if (now.getTime() > exitTime)
				return;
		}
	},
	/**
	 * @param {}  
	 * @return {String} uuid 返回uuid
	 */
	uuid() {
		return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
			(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
		);
	},
	/**
	 * @param {Function}  
	 * @return {String} time 返回程序所用时间
	 */
	timeConsum(callback) {
		console.time('timeTaken');
		const r = callback();
		console.timeEnd('timeTaken');
		return r;
	}
}